package com.novunda.platform.services;

import com.google.common.collect.Lists;
import com.novunda.platform.common.handler.LogCallBack;
import com.novunda.platform.common.utils.StringUtil;
import com.novunda.platform.common.utils.UserUtils;
import com.novunda.platform.common.web.modal.Page;
import com.novunda.platform.entities.Log;
import com.novunda.platform.entities.User;
import com.novunda.platform.repositories.UserRepository;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.Date;
import java.util.List;

/**
 * .
 * 功能说明：账号service
 *
 * @author linfeng
 * @version 1.0
 * @modify FJ
 * @see 2016年9月22日
 */
@Service
@Transactional
public class UserService extends BaseService {

    /**
     * .
     * 账号dao
     */
    @Autowired
    private UserRepository userRepository;

    /**
     * .
     * 功能说明：保存一次
     *
     * @param user 账号
     */
    @Transactional(readOnly = false)
    public void saveOnce(final User user) {
        handler.doHandler(new LogCallBack() {
            @Override
            public Object doHandler() {
                userRepository.save(user);
                return null;
            }

            @Override
            public Log generate() {
                Log log = new Log();
                String operation = user.getId() == null ? "添加" : "修改";
                log.setType(operation);
                log.setName(operation + "账号");
                log.setDescription(operation + "账号：" + user.getLoginName());
                return log;
            }

            @Override
            public boolean forceLog() {
                return false;
            }
        });
    }

    /**
     * .
     * 功能说明：保存账号
     *
     * @param user 账号
     * @return
     */
    @Transactional(readOnly = false)
    public User saveUser(final User user) {
        return (User) handler.doHandler(new LogCallBack() {
            @Override
            public Object doHandler() {
                return userRepository.save(user);
            }

            @Override
            public Log generate() {
                Log log = new Log();
                String operation = user.getId() == null ? "添加" : "修改";
                log.setType(operation);
                log.setName(operation + "账号");
                log.setDescription(operation + "账号：" + user.getLoginName());
                return log;
            }

            @Override
            public boolean forceLog() {
                return false;
            }
        });
    }

    /**
     * .
     * 功能说明：删除账号
     *
     * @param id
     */
    @Transactional(readOnly = false)
    public void deleteUser(final Long id) {
        handler.doHandler(new LogCallBack() {
            @Override
            public Object doHandler() {
                userRepository.deleteById(id);
                return null;
            }

            @Override
            public Log generate() {
                Log log = new Log();
                log.setType("删除");
                log.setName("删除账号");
                log.setDescription("删除账号id：" + id);
                return log;
            }

            @Override
            public boolean forceLog() {
                return false;
            }
        });
    }

    /**
     * .
     * 功能说明：通过账号名查询
     *
     * @param loginName 账号名
     * @return
     */
    public User findByLoginName(String loginName) {
        return userRepository.findByLoginName(loginName);
    }

    /**
     * .
     * 功能说明：查询所有账号
     *
     * @return
     */
    public List<User> findAllUsers() {
        return userRepository.findAll(new UserSpecification(new User()));
    }

    /**
     * .
     * 功能说明：通过token查询账号
     *
     * @param token 令牌
     * @return
     */
    public User findUserByToken(String token) {
        return userRepository.findUserByToken(token);
    }

    /**
     * .
     * 功能说明：修改账号信息
     *
     * @param id
     */
    @Transactional(readOnly = false)
    public void updateUserLoginInfo(final Long id) {
        handler.doHandler(new LogCallBack() {
            @Override
            public Object doHandler() {
                userRepository.updateLoginInfo(SecurityUtils.getSubject().getSession().getHost(), new Date(), id);
                return null;
            }

            @Override
            public Log generate() {
                Log log = new Log();
                log.setType("修改");
                log.setName("修改登录信息");
                log.setDescription("修改登录信息账号id：" + id);
                return log;
            }

            @Override
            public boolean forceLog() {
                return false;
            }
        });
    }

    /**
     * .
     * 功能说明：通过账号id查询
     *
     * @param id
     * @return
     */
    public User getUser(Long id) {
        return userRepository.get(id);
    }

    /**
     * .
     * 功能说明：分页条件查询账号
     *
     * @param page         分页对象
     * @param queryKeyWord 查询关键字
     * @param organization 机构
     * @return
     */
    public Page<User> findUserByPaging(Page<User> page, String queryKeyWord, String organization) {
        DetachedCriteria dc = userRepository.createDetachedCriteria();
        User currentUser = UserUtils.getUser();
        dc.createAlias("office", "office");
        dc.createAlias("company", "company");
        // 如果当前用户不是admin
        if (!currentUser.isAdmin() || StringUtil.isEmpty(organization)) {
            dc.add(dataScopeFilter(currentUser, "office", ""));
        }
        // 如果机构名不为空
        if (!StringUtil.isEmpty(organization)) {
            dc.add(Restrictions.eq("company.name", organization));
        }
        dc.add(Restrictions.ne("delFlag", "1"));
        dc.add(Restrictions.ne("id", 1L));
        // 如果关键字不为空
        if (!StringUtil.isEmpty(queryKeyWord)) {
            dc.add(Restrictions.or(Restrictions.like("realName", "%" + queryKeyWord + "%"),
                    Restrictions.like("email", "%" + queryKeyWord + "%"),
                    Restrictions.like("loginName", "%" + queryKeyWord + "%"),
                    Restrictions.like("company.name", "%" + queryKeyWord + "%")));
        }
        dc.addOrder(Order.desc("id"));
        return userRepository.find(page, dc);
    }

    /**
     * .
     * 功能说明：分页查询账号
     *
     * @param page 分页对象
     * @param user 账号对象
     * @return
     */
    public Page<User> findUser(Page<User> page, User user) {
        org.springframework.data.domain.Page<User> springPage = userRepository.findAll(new UserSpecification(user),
                page.getSpringPage());
        page.setSpringPage(springPage);
        return page;
    }

    /**
     * .
     * 功能说明：通过机构查询
     *
     * @param organization 机构
     * @return
     */
    public int findUserByOrganization(String organization) {
        User currentUser = UserUtils.getUser();
        // 判断是不是admin
        if (currentUser.isAdmin()) {
            return userRepository.findUserCountByAdmin();
        } else {
            return userRepository.findUserByOrganization(organization);
        }
    }

    /**
     * 机构下，未激活的账号总数
     *
     * @return 未激活的账号总数
     */
    public int queryNotActivateUser(String organization, String keyWord) {
        User currentUser = UserUtils.getUser();
        // 判断是不是admin
        if (currentUser.isAdmin()) {
            if (!StringUtil.isEmpty(organization)) {
                if (StringUtil.isEmpty(keyWord)) {
                    return userRepository.queryNotActivateUser(organization, "%%");
                } else {
                    return userRepository.queryNotActivateUser(organization, "%" + keyWord + "%");
                }
            } else {
                if (StringUtil.isEmpty(keyWord)) {
                    return userRepository.queryAdminNotActivateUser("%%");
                } else {
                    return userRepository.queryAdminNotActivateUser("%" + keyWord + "%");
                }
            }
        } else {
            if (!StringUtil.isEmpty(organization)) {
                if (StringUtil.isEmpty(keyWord)) {
                    return userRepository.queryNotActivateUser(organization, "%%");
                } else {
                    return userRepository.queryNotActivateUser(organization, "%" + keyWord + "%");
                }
            } else {
                DetachedCriteria dc = userRepository.createDetachedCriteria();
                dc.createAlias("office", "office");
                dc.createAlias("company", "company");
                dc.add(dataScopeFilter(currentUser, "office", ""));
                dc.add(Restrictions.ne("delFlag", "1"));
                dc.add(Restrictions.eq("bindStatus", 0));
                dc.add(Restrictions.ne("id", 1L));
                // 如果关键字不为空
                if (!StringUtil.isEmpty(keyWord)) {
                    dc.add(Restrictions.or(Restrictions.like("realName", "%" + keyWord + "%"),
                            Restrictions.like("email", "%" + keyWord + "%"),
                            Restrictions.like("loginName", "%" + keyWord + "%"),
                            Restrictions.like("company.name", "%" + keyWord + "%")));
                }
                return userRepository.queryNotActivateUser(dc);
            }
        }
    }

    /**
     * .
     * 功能说明：通过机构查询
     *
     * @return
     */
    public int queryActivateUser(String organization, String keyWord) {
        User currentUser = UserUtils.getUser();
        // 判断是不是admin
        if (currentUser.isAdmin()) {
            if (!StringUtil.isEmpty(organization)) {
                if (StringUtil.isEmpty(keyWord)) {
                    return userRepository.queryActivateUser(organization, "%%");
                } else {
                    return userRepository.queryActivateUser(organization, "%" + keyWord + "%");
                }
            } else {
                if (StringUtil.isEmpty(keyWord)) {
                    return userRepository.queryActivateUserByAdmin("%%");
                } else {
                    return userRepository.queryActivateUserByAdmin("%" + keyWord + "%");
                }
            }
        } else {
            if (!StringUtil.isEmpty(organization)) {
                return userRepository.queryActivateUser(organization, "%" + keyWord + "%");
            } else {
                DetachedCriteria dc = userRepository.createDetachedCriteria();
                dc.createAlias("office", "office");
                dc.createAlias("company", "company");
                dc.add(dataScopeFilter(currentUser, "office", ""));
                dc.add(Restrictions.ne("delFlag", "1"));
                dc.add(Restrictions.eq("bindStatus", 1));
                dc.add(Restrictions.ne("id", 1L));
                // 如果关键字不为空
                if (!StringUtil.isEmpty(keyWord)) {
                    dc.add(Restrictions.or(Restrictions.like("realName", "%" + keyWord + "%"),
                            Restrictions.like("email", "%" + keyWord + "%"),
                            Restrictions.like("loginName", "%" + keyWord + "%"),
                            Restrictions.like("company.name", "%" + keyWord + "%")));
                }
                return userRepository.queryActivateUser(dc);
            }
        }
    }

    /**
     * .
     * 功能说明：查询条件过滤
     *
     * @author FJ
     * @version 1.0
     * @see 2016年9月22日
     */
    private static class UserSpecification implements Specification<User> {

        private final User user;

        UserSpecification(User user) {
            this.user = user;
        }

        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {

            List<Predicate> predicateList = Lists.newArrayList();
            if (StringUtils.isNotBlank(user.getLoginName())) {
                predicateList.add(getUsernamePredicate(root, criteriaBuilder));
            }
            User currentUser = UserUtils.getUser();
            if (currentUser.isAdmin()) {
                predicateList.add(criteriaBuilder.equal(root.get("id").as(Long.class), 1L));
            }
            Predicate[] predicateArray = new Predicate[predicateList.size()];
            criteriaQuery.where(criteriaBuilder.and(predicateList.toArray(predicateArray)));
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("id").as(Long.class)));
            return criteriaQuery.getRestriction();

        }

        private Predicate getUsernamePredicate(Root<User> root, CriteriaBuilder criteriaBuilder) {
            return criteriaBuilder.like(root.get("loginName").as(String.class), "%" + user.getLoginName() + "%");
        }

    }

    /**
     * . 功能说明：通过邮箱和机构查询帐号
     *
     * @param email 邮箱
     * @param orgId 机构id
     * @return
     */
    public User findUserByEmailOrg(String email, long orgId) {
        return userRepository.findUserByEmailAndOffice(email, orgId);
    }

    /**
     * .
     * 功能说明：保存账号
     *
     * @param user 账号
     * @return
     */
    @Transactional(readOnly = false)
    public void changeUserState(final User user) {
        handler.doHandler(new LogCallBack() {
            @Override
            public Object doHandler() {
                userRepository.save(user);
                return null;
            }

            @Override
            public Log generate() {
                Log log = new Log();
                String operation = user.getState() == 0 ? "解冻" : "冻结";
                log.setType(operation);
                log.setName(operation + "账号");
                log.setDescription(operation + "账号：" + user.getLoginName());
                return log;
            }

            @Override
            public boolean forceLog() {
                return false;
            }
        });
    }

    @Transactional(readOnly = false)
    public void updateStatus(int state, final Long userId) {
        userRepository.updateStatus(state, userId);
    }
}
